/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.oai.metadataRepository.tools;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 *
 * @author Martin Rehanek, Martin.Rehanek@gmail.com
 */
public class FileTools {

    /**
     * Reads files in dir and returns List of their relative names
     * @param dir directory to be read
     * @return List of file names. The names are just last names in the path, i.e. names of the files in directory dir.
     * For directory /home/user/work and file /home/user/work/file.xml only 'file.xml' will be present in List<String> returned
     * @throws CannotReadDirectoryException if following bug happens
     * I found a bug in implemenation of methods java.io.File.list() and java.io.File.listFiles()
     * File dir = new Fil("/some/path/to/a/dir");
     * Sometimes dir.list() and dir.listFiles() returns null even if:
     * 1. dir.exist() == true
     * 2. dir.isDirectory() == true
     * 3. dir.canRead() == true;
     * It's slightly predictable. It has allways happent after creating about thousands of File instances
     * (not only dirs but also ordinary files).
     * The bug has been previously noted and described here:
     * https://issuetracker.springsource.com/browse/DMS-2489
     */
    public static List<String> readFilenames(File dir) throws CannotReadDirectoryException {
        //System.out.println("dir: " + dir);
        //FIXME: nekdy vraci dir.list() null i kdyz je dir platnym adresarem
        //napr. /home/martin/tmp/metadata-collections/mollMapsAfter1800/marc21
        //nechapu zdroj teto chyby. Projevuje se jen nedky a je tezke ji replikovat.
        //System.out.println(dir.getTotalSpace());
        if (dir.exists() && dir.isDirectory() && dir.canRead()) {
            String[] files = dir.list();
//          System.out.println("dir: " + dir.getAbsolutePath());
//          System.out.println("can read: " + dir.canRead());
//          System.out.println("can execute: " + dir.canExecute());
//          System.out.println("can write: "  + dir.canWrite());
            if (files == null) {
                //File file = new File(dir.getAbsoluteFile() + File.separator + "oai%3Aaleph.mzk.cz%3AMZK03-001053340.xml");
                //System.out.println("file exists: " + file.exists());
                //System.out.println("dir.execut(): " + dir.canExecute());
                //System.out.println("listFiles==null? " + (dir.listFiles() == null));
//              File dir2 = new File(dir.getAbsolutePath());
//              if (dir2.list() == null){
//                 System.err.println("dir2.list() == null");
//              }
                //if (dir2.list() == null)
//              File test = new File(dir.getAbsolutePath() + File.separator + "oai%3Aaleph.mzk.cz%3AMZK03-001053401.xml");
//              System.out.println("test: " + test.toString());
//              System.out.println("test.exists: " + test.exists());
                throw new CannotReadDirectoryException(dir.getAbsolutePath());
            } else {
                return Arrays.asList(files);
            }
//        return readFiles2(dir);
        } else {
            throw new IllegalArgumentException(dir.getAbsolutePath());
        }
    }

    /**
     * Reads files in dir and returns List of their absolute names
     * @param dir directory to be read
     * @return List of absolute file names, i.e. the file with whole path.
     * For directory /home/user/work and file /home/user/work/file.xml whole '/home/user/work/file.xml' will be present in List<String> returned
     * @throws CannotReadDirectoryException if following bug happens
     * I found a bug in implemenation of methods java.io.File.list() and java.io.File.listFiles()
     * File dir = new Fil("/some/path/to/a/dir");
     * Sometimes dir.list() and dir.listFiles() returns null even if:
     * 1. dir.exist() == true
     * 2. dir.isDirectory() == true
     * 3. dir.canRead() == true;
     * It's slightly predictable. It has allways happent after creating about thousands of File instances
     * (not only dirs but also ordinary files).
     * The bug has been previously noted and described here:
     * https://issuetracker.springsource.com/browse/DMS-2489
     */
    public static List<String> readAbsoluteFilenames(File dir) throws CannotReadDirectoryException {
        List<String> relativeNames = readFilenames(dir);
        List<String> absoluteNames = new ArrayList<String>(relativeNames.size());
        String dirAbsoluteName = dir.getAbsolutePath();
        for (String name : relativeNames) {
            StringBuilder absoluteName = new StringBuilder();
            absoluteName.append(dirAbsoluteName);
            absoluteName.append(File.separatorChar);
            absoluteName.append(name);
            absoluteNames.add(absoluteName.toString());
        }
        return absoluteNames;
    }

    /**
     * Reads files in dir and returns List of java.io.File
     * @param dir directory to be read
     * @return List of Files
     * @throws CannotReadDirectoryException if following bug happens
     * I found a bug in implemenation of methods java.io.File.list() and java.io.File.listFiles()
     * File dir = new Fil("/some/path/to/a/dir");
     * Sometimes dir.list() and dir.listFiles() returns null even if:
     * 1. dir.exist() == true
     * 2. dir.isDirectory() == true
     * 3. dir.canRead() == true;
     * It's slightly predictable. It has allways happent after creating about thousands of File instances
     * (not only dirs but also ordinary files).
     * The bug has been previously noted and described here:
     * https://issuetracker.springsource.com/browse/DMS-2489
     */
    public static List<File> readFiles(File dir) throws CannotReadDirectoryException {
        List<String> relativeNames = readFilenames(dir);
        List<File> files = new ArrayList<File>(relativeNames.size());
        String dirAbsoluteName = dir.getAbsolutePath();
        for (String name : relativeNames) {
            StringBuilder absoluteName = new StringBuilder();
            absoluteName.append(dirAbsoluteName);
            absoluteName.append(File.separatorChar);
            absoluteName.append(name);
            files.add(new File(absoluteName.toString()));
        }
        return files;
    }

    private static List<String> readFiles2(File dir) {
        File[] files = dir.listFiles();
        List<String> result = new ArrayList<String>(files.length);
        for (int i = 0; i < files.length; i++) {
            result.add(files[i].getName());
        }
        return result;
    }

    /**
     * @param filename
     * @return true if file has been successfuly removed, false otherwise
     */
    public static boolean removeFile(String filename) {
        File file = new File(filename);
        return file.delete();
    }

    /**
     * Creates absolute file name from root file, list of subdirectories and filename.
     * @param rootDir
     * @param subDirs
     * @param filename
     * @return rootDir/subDirs[0]/subDirs[1]/.../subDirs[subDirs.size()-1]/filename
     */
    public static String buildAbsoluteFilename(String rootDir, List<String> subDirs, String filename) {
        StringBuilder builder = new StringBuilder();
        builder.append(rootDir);
        builder.append(File.separatorChar);
        for (String dir : subDirs) {
            builder.append(dir);
            builder.append(File.separatorChar);
        }
        builder.append(filename);
        return builder.toString();
    }

    public static String buildFilePath(String root, String subDir, String fileName) {
        StringBuilder builder = new StringBuilder();
        builder.append(root);
        builder.append(File.separatorChar);
        builder.append(subDir);
        builder.append(File.separatorChar);
        builder.append(fileName);
        return builder.toString();
    }

    public static String buildSubdirPath(String root, String subDir) {
        StringBuilder builder = new StringBuilder();
        builder.append(root);
        builder.append(File.separatorChar);
        builder.append(subDir);
        return builder.toString();
    }
}
